package com.javacv4axe.core;

import org.axe.util.LogUtil;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.OpenCVFrameGrabber;

/**
 * 监控类 根据指定的发现策略（发现人脸或者二维码...），发现目标后交给handle处理 自带画面防抖
 */
public final class CammeraWatcher {
	
	private int imageWidth = 0;
	private int imageHeight = 0;
	
	// 是否在运行
	private Boolean isRuning = false;

	private AsynchronousFrameHandler[] detectHandles = null;

	private CammeraStartFailed startFailed = null;

	private boolean debug = false;

	/**
	 * 非线程安全，所以最好1个线程设置
	 */
	public void debug() {
		debug = true;
	}

	public CammeraWatcher(int imageWidth,int imageHeight,CammeraStartFailed startFailed, AsynchronousFrameHandler... detectHandles) {
		this.imageWidth = imageWidth;
		this.imageHeight = imageHeight;
		this.startFailed = startFailed;
		this.detectHandles = detectHandles;
		for(AsynchronousFrameHandler handler:detectHandles){
			handler.setCammeraWatcher(this);
		}
	}
	
	public CammeraWatcher(CammeraStartFailed startFailed, AsynchronousFrameHandler... detectHandles) {
		this.startFailed = startFailed;
		this.detectHandles = detectHandles;
		for(AsynchronousFrameHandler handler:detectHandles){
			handler.setCammeraWatcher(this);
		}
	}

	public CammeraWatcher(int imageWidth,int imageHeight,AsynchronousFrameHandler... detectHandles) {
		this.imageWidth = imageWidth;
		this.imageHeight = imageHeight;
		this.detectHandles = detectHandles;
		for(AsynchronousFrameHandler handler:detectHandles){
			handler.setCammeraWatcher(this);
		}
	}
	
	public CammeraWatcher(AsynchronousFrameHandler... detectHandles) {
		this.detectHandles = detectHandles;
		for(AsynchronousFrameHandler handler:detectHandles){
			handler.setCammeraWatcher(this);
		}
	}

	public void stopWatch() {
		synchronized (isRuning) {
			isRuning = false;
		}
	}
	
	public void startWatch(){
		startWatch(-1);//默认从-1设备序号开始找摄像头
	}

	public void startWatch(final int cammeraIndexStart) {
		synchronized (isRuning) {
			if(isRuning){
				if(debug){
					LogUtil.log("禁止重复启动摄像头...");
				}
				//说明正在运行
				return;
			}
		}
		
		if(debug){
			LogUtil.log("启动摄像头...");
		}
		isRuning = true;//开始运行
		new Thread("CammeraWatcher"){
			/**
			 * 开始监控摄像头
			 */
			public void run() {
				// 初始化摄像头等操作
				OpenCVFrameGrabber grabber = null;
				try {
					// 遍历查找摄像头
					for (int i = cammeraIndexStart; i < 5; i++) {
						try {
							grabber = new OpenCVFrameGrabber(i);
							if(imageWidth != 0 && imageHeight != 0){
								grabber.setImageWidth(imageWidth);
								grabber.setImageHeight(imageHeight);
							}
							grabber.start();
							grabber.grab();// 尝试抓取1帧
							// 找到摄像头设备，退出遍历
							if(debug){
								LogUtil.log("获取本机当前摄像头序号：" + i);
							}
							break;
						} catch (Exception e) {
							if (grabber != null) {
								try {
									grabber.stop();
								} catch (Exception e2) {
								}
								try {
									grabber.close();
								} catch (Exception e2) {
								}
							}
							grabber = null;
						}
					}

					if (grabber == null) {
						CammeraWatcher.this.isRuning = false;
						LogUtil.error("摄像头启动失败，未发现可用的设备");
						if(CammeraWatcher.this.startFailed != null){
							CammeraWatcher.this.startFailed.process("摄像头启动失败，未发现可用的设备");
						}
						return;
					}

					while (true) {
						if (!CammeraWatcher.this.isRuning) {
							synchronized (CammeraWatcher.this.isRuning) {
								if (!CammeraWatcher.this.isRuning) {
									break;
								}
							}
						}

						Frame frame = grabber.grab();// 重新获取frame
						do {
							if (frame == null) {// 读取一帧frame图像
								break;
							}
							// 读取到了frame
							FramePack fp = new FramePack(frame);
							for (AsynchronousFrameHandler handle : CammeraWatcher.this.detectHandles) {
								handle.cacheFrame(fp);
							}

						} while (false);
					}
				} catch (Exception e) {
					LogUtil.error(e);
				} finally {
					if (grabber != null) {
						try {
							grabber.close();
						} catch (Exception e2) {
						}
					}
					if (CammeraWatcher.this.isRuning) {
						run();// 重新run
					}
					if(debug){
						LogUtil.log("摄像头退出");
					}
				}
			}
		}.start();
	}
	
	public boolean isRuningStatus(){
		synchronized (isRuning) {
			return isRuning.booleanValue();
		}
	}
}
